package com.cliff.joinus;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Properties;

import org.cybergarage.net.HostInterface;

import android.util.Log;

import com.cliff.joinus.dataobject.ImageItem;
import com.cliff.joinus.dataobject.MusicItem;
import com.cliff.joinus.dataobject.VideoItem;
import com.cliff.joinus.misc.NanoHTTPD;

public class MicroHTTPD extends NanoHTTPD {

	protected static int PORT = 8192;
	
	protected final String ERROR_404_INVALID_URL = "Error 404, Invalid URL.";
	protected final String ERROR_404_NOT_FOUND = "Error 404, file not found.";
	protected final String ERROR_404_ARRAY_OUTOF_BOUNDS = "Error 404, Array out of bounds.";

	protected static final String PREFIX_IMAGE_LIST_URL = "/imagelist/"; 
	protected static final String PREFIX_MUSIC_LIST_URL = "/musiclist/"; 
	protected static final String PREFIX_VIDEO_LIST_URL = "/videolist/";
	
	protected static String localIp = null;
	
	protected final String TAG = "MicroHTTPD";

	public MicroHTTPD() throws IOException {
		super(PORT, null);
		localIp = HostInterface.getIPv4Address();
	}

	public Response serveFile(String uri, Properties header) {
		Log.d(TAG, "serveFile:uri="+uri);
		Response res = null;

		File f = new File(uri);
		if (res == null && !f.exists())
			res = new Response(HTTP_NOTFOUND, MIME_PLAINTEXT,
					ERROR_404_NOT_FOUND);

		// List the directory, if necessary
		if (res == null && f.isDirectory()) {
			res = new Response(HTTP_FORBIDDEN, MIME_PLAINTEXT,
					"FORBIDDEN: No directory listing.");
		}

		try {
			if (res == null) {
				// Get MIME type from file name extension, if possible
				String mime = null;
				int dot = f.getCanonicalPath().lastIndexOf('.');
				if (dot >= 0)
					mime = (String) theMimeTypes.get(f.getCanonicalPath()
							.substring(dot + 1).toLowerCase());
				if (mime == null)
					mime = MIME_DEFAULT_BINARY;

				// Calculate etag
				String etag = Integer.toHexString((f.getAbsolutePath()
						+ f.lastModified() + "" + f.length()).hashCode());

				// Support (simple) skipping:
				long startFrom = 0;
				long endAt = -1;
				String range = header.getProperty("range");
				if (range != null) {
					if (range.startsWith("bytes=")) {
						range = range.substring("bytes=".length());
						int minus = range.indexOf('-');
						try {
							if (minus > 0) {
								startFrom = Long.parseLong(range.substring(0,
										minus));
								endAt = Long.parseLong(range
										.substring(minus + 1));
							}
						} catch (NumberFormatException nfe) {
						}
					}
				}

				// Change return code and add Content-Range header when skipping
				// is requested
				long fileLen = f.length();
				if (range != null && startFrom >= 0) {
					if (startFrom >= fileLen) {
						res = new Response(HTTP_RANGE_NOT_SATISFIABLE,
								MIME_PLAINTEXT, "");
						res.addHeader("Content-Range", "bytes 0-0/" + fileLen);
						res.addHeader("ETag", etag);
					} else {
						if (endAt < 0)
							endAt = fileLen - 1;
						long newLen = endAt - startFrom + 1;
						if (newLen < 0)
							newLen = 0;

						final long dataLen = newLen;
						FileInputStream fis = new FileInputStream(f) {
							public int available() throws IOException {
								return (int) dataLen;
							}
						};
						fis.skip(startFrom);

						res = new Response(HTTP_PARTIALCONTENT, mime, fis);
						res.addHeader("Content-Length", "" + dataLen);
						res.addHeader("Content-Range", "bytes " + startFrom
								+ "-" + endAt + "/" + fileLen);
						res.addHeader("ETag", etag);
					}
				} else {
					if (etag.equals(header.getProperty("if-none-match")))
						res = new Response(HTTP_NOTMODIFIED, mime, "");
					else {
						res = new Response(HTTP_OK, mime,
								new FileInputStream(f));
						res.addHeader("Content-Length", "" + fileLen);
						res.addHeader("ETag", etag);
					}
				}
			}
		} catch (IOException ioe) {
			res = new Response(HTTP_FORBIDDEN, MIME_PLAINTEXT,
					"FORBIDDEN: Reading file failed.");
		}

		res.addHeader("Accept-Ranges", "bytes"); // Announce that the file
													// server accepts partial
													// content requestes
		return res;
	}
	
	@Override
	public Response serve(String uri, String method,
			Properties header, Properties parms, Properties files) {
		
		int pos = 0;
		String error = null;

		if (uri.startsWith(PREFIX_IMAGE_LIST_URL)) {			
			try {
				pos = Integer.parseInt(uri.substring(PREFIX_IMAGE_LIST_URL.length()));
				ArrayList<ImageItem> array = LocalMediaDataManager.getInstance().getImageList(); 
				if ((pos < 0) || (pos >= array.size())) {
					error = ERROR_404_ARRAY_OUTOF_BOUNDS;
				}
				return serveFile(array.get(pos).filePathName, header);
			} catch (Exception ex) {
				error = ERROR_404_INVALID_URL;
			}
		} 
		else if (uri.startsWith(PREFIX_MUSIC_LIST_URL)) {			
			try {
				pos = Integer.parseInt(uri.substring(PREFIX_MUSIC_LIST_URL.length()));
				ArrayList<MusicItem> array = LocalMediaDataManager.getInstance().getMusicList(); 
				if ((pos < 0) || (pos >= array.size())) {
					error = ERROR_404_ARRAY_OUTOF_BOUNDS;
				}
				return serveFile(array.get(pos).filePathName, header);
			} catch (Exception ex) {
				error = ERROR_404_INVALID_URL;
			}
		} 
		else if (uri.startsWith(PREFIX_VIDEO_LIST_URL)) {			
			try {
				pos = Integer.parseInt(uri.substring(PREFIX_VIDEO_LIST_URL.length()));
				ArrayList<VideoItem> array = LocalMediaDataManager.getInstance().getVideoList(); 
				if ((pos < 0) || (pos >= array.size())) {
					error = ERROR_404_ARRAY_OUTOF_BOUNDS;
				}
				return serveFile(array.get(pos).filePathName, header);
			} catch (Exception ex) {
				error = ERROR_404_INVALID_URL;
			}
		} 
		else
			error = ERROR_404_NOT_FOUND;
		
		return new Response(HTTP_NOTFOUND, MIME_PLAINTEXT,
				error);
	}
	
	public static String getLocalImageUrl(int pos) {
		return "http://"+localIp+":"+PORT+PREFIX_IMAGE_LIST_URL+pos;
	}

	public static String getLocalAudioUrl(int pos) {
		return "http://"+localIp+":"+PORT+PREFIX_MUSIC_LIST_URL+pos;
	}

	public static String getLocalVideoUrl(int pos) {
		return "http://"+localIp+":"+PORT+PREFIX_VIDEO_LIST_URL+pos;
	}
	
}
